﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DNASequencing.core.data;
using DNASequencing.core.Algorithms.rating;

namespace DNASequencing.core.Algorithms
{
    /// <summary>
    /// Decorator for <code>AOligonucleotide</code>. Adds functionality
    /// used in algorithm.
    /// </summary>
    class Oligonucleotide : AOligonucleotide
    {
        /// <summary>
        /// Negative error of oligonucletide. 
        /// <br/>0 if there is no error.
        /// <br/>-1 if variable is not set.
        /// </summary>
        public int error = -1;
        //public bool used = false;

        /// <summary>
        /// Original object that is packes into this.
        /// </summary>
        protected AOligonucleotide _oOriginal;

        //protected double sortRating = -1;

        /// <summary>
        /// Original object that is packed into this.
        /// </summary>
        public AOligonucleotide original
        {
            get
            {
                return _oOriginal;
            }
        }

        new public Boolean used
        {
            get
            {
                return original.used;
            }
            set
            {
                original.used = value;
            }
        }

        new public List<Oligonucleotide> best
        {
            get
            {
                return original.best;
            }
            set
            {
                original.best = value;
            }
        }

        new public double rating
        {
            get
            {
                return original.rating;
            }
            set
            {
                original.rating = value;
            }
        }

        new public List<AOligonucleotide>[] next
        {
            get
            {
                return original.next;
            }
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="original">Original object.</param>
        public Oligonucleotide(AOligonucleotide original)
            : base(original.originalSequence)
        {
            _oOriginal = original;
        }

        public Oligonucleotide(Oligonucleotide toCopy)
            : base(toCopy.originalSequence)
        {
            //used = toCopy.used;
            _oOriginal = toCopy.original;
            _oOriginal.used = toCopy.original.used;
            error = toCopy.error;
        }

        /// <summary>
        /// Compares two oligonucleotides.
        /// </summary>
        /// <param name="o1">First oligonucleotide.</param>
        /// <param name="o2">Second oligonucleotide<./param>
        /// <returns>Integer that describes relation between objects:
        /// <br/>-1 if o1 is better than o2
        /// <br/>1 if o2 is better than o1
        /// <br/>0 if objects are equal</returns></returns></returns></returns>
        public static int compare(Oligonucleotide o1, Oligonucleotide o2)
        {
            if (o1.rating > o2.rating)
                return -1;
            else if (o1.rating < o2.rating)
                return 1;
            else
                return 0;
        }

        private bool listContains(List<Oligonucleotide> list, AOligonucleotide el)
        {
            foreach (Oligonucleotide o in list)
                if (o.originalSequence == el.originalSequence)
                    return true;
            return false;
        }

        /// <summary>
        /// Extracts <code>k</code> best followers from all followers held in <code>next</code>
        /// table of lists.
        /// </summary>
        /// <param name="k">Number of best elements.</param>
        /// <returns>Table with <code>k</code> best elements.</returns>
        public Oligonucleotide[] getBest(int k, IRating rating)
        {
            List<Oligonucleotide> allNext = new List<Oligonucleotide>();
            int error = 0;

            foreach (List<AOligonucleotide> next in original.next)
            {
                foreach (AOligonucleotide o in next)
                {
                    Oligonucleotide oWithError = new Oligonucleotide(o);
                    oWithError.error = error;
                    rating.rate(oWithError);
                    allNext.Add(oWithError);
                }
                ++error;
            }

            allNext.Sort(compare);

            int i = 0;
            int j = 0;
            List<Oligonucleotide> result = new List<Oligonucleotide>();
            while (i < k)
            {
                if (allNext.ElementAt(j).original.used == false)
                {
                    result.Add(allNext.ElementAt(j));
                    i++;
                }
                j++;
                if (allNext.Count == j)
                    i = k;
            }
            return result.ToArray();
        }

        /// <summary>
        /// Sequence of aminoacids.
        /// </summary>
        override public String getSequence()
        {
            return _sAminoacids;
        }
    }
}
